import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, IsNull, Not, Repository } from 'typeorm';
import DataBase from '../../config/database'
import { Cron, Timeout, Interval } from '@nestjs/schedule';
import { RedisInstance } from 'src/common/redis';
import { Questions } from './questions.entity';
import { Notices } from '../notices/notices.entity';
import { NoticeCheckEnum, NoticeTypeEnum } from '../notices/notices.enum';
import { Profit } from '../profit/profit.entity';
import { Reward } from '../reward/reward.entity';
import { payStatusEnum } from '../reward/reward.enum';
import { profitEnum, profitTypeEnum } from '../profit/profit.enum';
import utils from 'src/common/utils';
import { existsSync, unlinkSync, writeFileSync } from 'fs';
import { WsStartGateway } from '../ws/ws.gateway';
import { Answer } from '../answer/answer.entity';
let redisKey = 'post_answer_' + (process.env.post_answer || 'local')
let autoSecond = 60 * 1

@Injectable()
export class QuestionsServiceTimer {
  constructor(
    @InjectRepository(Questions)
    private repository: Repository<Questions>,
    @InjectRepository(Notices)
    private noticesRepository: Repository<Notices>,
    @InjectRepository(Profit)
    private profitRepository: Repository<Profit>,
    @InjectRepository(Reward)
    private rewardRepository: Repository<Reward>,
    @InjectRepository(Answer)
    private answerRepository: Repository<Answer>,
    private readonly wsStartGateway: WsStartGateway,
  ) {}


  // @Timeout(100)
  // async SearchMedia(){
  //   utils.SearchMedia([1164723]).then(res => {
  //     let list = res.MediaInfoSet
  //     console.log(list.length)
  //     let sql = []
  //     list.map(e => {
  //       let video_ratio = `${e.MetaData.Width}*${e.MetaData.Height}`
  //       sql.push(`insert into video(video_id, video_cover, create_time, update_time, video_key, video_ratio, ic_group, wx_user, ${'`check`'}, type, original, check_time, source, profit_type, overseas) values(${e.FileId}, '${e.BasicInfo.MediaUrl}', now(), now(), '${utils.guid()}', '${video_ratio}', 41, 'oGCIM6wIzmDJoqPBYsci5JgpWsHY', 1, 1, 1, check_time, 0, 0, 1);`)
  //     })
  //     let sqlurl = `C:\\fx\\MyProject\\短视频\\projects\\server\\Microservice\\server_microservice_auto_postanswer\\sql.sql`
  //     if(existsSync(sqlurl)){
  //       unlinkSync(sqlurl)
  //     }
  //     writeFileSync(sqlurl, sql.join('\r\n'))
  //   }).catch(err => {
  //     console.log(err,'err')
  //   })
  // }

  sismember(client, id){
    return new Promise((resolve, reject) => {
      client.sismember(redisKey, id, (err, isMember) => {
        console.log(isMember); // 如果元素存在，输出 1；如果不存在，输出 0
        resolve(isMember == 1 ? true : false)
      });
    })
  }
  sadd(client, id){
    return new Promise((resolve, reject) => {
      client.sadd(redisKey, id, (err, reply) => {
        console.log(reply); // 输出添加的元素数量
        resolve(reply > 0)
      });
    })
  }

  // 移除集合中的元素
  srem(client, id){
    return new Promise((resolve, reject) => {
      client.srem(redisKey, id, (err, reply) => {
        console.log(reply); // 输出移除的元素数量
        resolve(reply > 0)
      });
    })
  }

  async startHandle(list: Questions[], noticeList: Notices[], profitList: Profit[], changeRewardList: Reward[], rejectAnswerList: Answer[], client){
    return new Promise(async (resolve, reject) => {
      let db: DataBase = new DataBase()
      let connection = await db.getConnection()
      const queryRunner = connection.createQueryRunner()
      await queryRunner.connect()
      // 开始事务
      await queryRunner.startTransaction()
      let removeRedis = () => {
        return new Promise((resolve2, reject2) => {
          let max = list.length - 1
          list.map(async (e,index) => {
            await this.srem(client, e.id)
            if(index === max){
              resolve2(true)
            }
          })
        })
      }
      try {
        let post_time = new Date()
        await this.repository.createQueryBuilder(null, queryRunner).update({post_answer: 1}).where({id: In(list.map(e => e.id))}).execute()
        if(rejectAnswerList.length > 0){
          await this.answerRepository.createQueryBuilder(null, queryRunner).update({check: 0, check_time: post_time, reject_auto_time: post_time}).where({id: In(rejectAnswerList.map(e => e.id))}).execute()
        }
        if(profitList.length > 0){
          await this.profitRepository.createQueryBuilder(null, queryRunner).insert().into(Profit).values(profitList).execute()
        }
        if(changeRewardList.length > 0){
          await this.rewardRepository.createQueryBuilder(null, queryRunner).update({pay_status: payStatusEnum.used}).where(changeRewardList).execute()
        }
        noticeList.map(e => {
          e.create_time = post_time
        })
        await this.noticesRepository.createQueryBuilder(null, queryRunner).insert().into(Notices).values(noticeList).execute()

        await queryRunner.commitTransaction()
        await queryRunner.release();
        await removeRedis()

        
        let noticeWxUserList = [...new Set([...noticeList.map(e => e.wx_user)])]
        console.log(noticeWxUserList,'noticeWxUserListnoticeWxUserList')
        noticeWxUserList.map(e => {
          //添加通知
          this.wsStartGateway.postUpdateNotice(e, e)
        })
        let video_ids = [...new Set([...list.map(e => e.video_id)])]
        console.log(video_ids,'video_idsvideo_ids')
        video_ids.map(e => {
          //更新视频数据
          this.wsStartGateway.postUpdateVideo(e)
        })

        //更新我的里数据
        list.map(e => {
          this.wsStartGateway.postUpdateMyData(e.wx_user, e.video_id)
        })
        
        resolve(true)
      } catch (err) {
        console.log(err,'err1')
        // 有错误做出回滚更改
        await queryRunner.rollbackTransaction()
        await queryRunner.release();
        await removeRedis()
        resolve(true)
      }
    })
  }

  @Interval(1000 * 30)
  async batchHandlePostAnswer(){
    let {
      list,
      rewardList,
      answerList
    } = await this.findPostAnswer()
    if(list.length > 0){
      const client = RedisInstance.initRedis();
      let changeList: Questions[] = []
      let noticesList: Notices[] = []
      let insertProfitList: Profit[] = []
      let changeRewardList: any = []
      let rejectAnswerList: Answer[] = []
      let nowTime = new Date()
      rewardList.map(e => {
        let reward = new Reward()
        reward.video_id = e.video_id
        reward.wx_user = e.wx_user
        changeRewardList.push(reward)

        let profit = new Profit();
        profit.author_wx_user = e.author_wx_user
        profit.use_wx_user = e.wx_user
        profit.unit_price = e.unit_price - e.service_charge
        profit.service_charge = e.service_charge
        profit.create_time = new Date()
        profit.update_time = new Date()
        profit.status = profitEnum.entry
        profit.type = profitTypeEnum.consume
        profit.answer_id = e.answer_id
        insertProfitList.push(profit)
      })
      answerList.map(e => {
        let addAnswer = new Answer()
        addAnswer.id = e.id
        rejectAnswerList.push(addAnswer)

        let notice = new Notices()
        notice.create_time = nowTime
        notice.video_id = e.video_id
        notice.wx_user = e.wx_user
        notice.check = NoticeCheckEnum.no
        notice.type = NoticeTypeEnum.answer_reject
        notice.answer_id = e.id
        notice.reject_reason = e.reject_reason
        noticesList.push(notice)
      })

      let max = list.length - 1
      let callback = async () => {
        await this.startHandle(changeList, noticesList, insertProfitList, changeRewardList, rejectAnswerList, client)
        client.quit()
      }
      list.map(async (e, index) => {
        let exist = await this.sismember(client, e.id)
        if(!exist){
          let question = new Questions()
          question.id = e.id
          question.video_id = e.video_id
          question.wx_user = e.wx_user
          changeList.push(question)
          
          //添加通知
          let notice = new Notices()
          notice.video_id = e.video_id
          notice.answer_id = e.answer_id
          notice.wx_user = e.wx_user
          notice.check = 1
          notice.type = NoticeTypeEnum.question_is_answer
          notice.create_time = new Date()
          noticesList.push(notice)
          this.sadd(client, e.id)
        }
        if(index === max){
          callback()
        }
      })
    }
  }

  async findPostAnswer(){
    let list = await this.repository.query(`
      select questions.id, questions.video_id, answer.id as answer_id, questions.wx_user, questions.group_uid
      from questions
      left join answer on answer.video_id = questions.video_id and answer.check = 1
      where now() >= questions.answer_time and questions.answer_time is not null and questions.post_answer is null
      order by questions.id asc
      limit 0,10
    `,[autoSecond])
    let newList = list

    let rewardSql = []
    let whereList = []
    newList.map(e => {
      rewardSql.push(` (reward_success.video_id = ? and reward_success.wx_user = ?)`)
      whereList.push(e.video_id)
      whereList.push(e.wx_user)
    })

    let rewardList = []
    if(rewardSql.length > 0){
      rewardList = await this.repository.query(`
        select reward_success.*, answer.wx_user as author_wx_user, answer.id as answer_id from reward_success
        inner join answer on answer.video_id = reward_success.video_id and answer.check = 1
        where ${rewardSql.join(' or ')}
      `,whereList)
    }

    let answerList = []
    let answerWhere = []
    let where = []
    newList.map(e => {
      answerWhere.push(` (answer.group_uid = ? and answer.video_id = ? ) `)
      where.push(e.group_uid)
      where.push(e.video_id)
    })
    if(answerWhere.length > 0){
      answerList = await this.repository.query(`
        select * from answer
        where answer.check is null and (${answerWhere.join(` or `)})
      `, where)
    }

    return {list: newList, rewardList: rewardList, answerList: answerList}
  }

  @Interval(1000 * 30)
  async batchHandleRejectAnswer(){
    let nowTime = new Date()
    let {
      answerList,
      questionsList
    } = await this.findRejectAnswer(nowTime)
    console.log(answerList,'====answerList')
    if(answerList.length > 0){
      let db: DataBase = new DataBase()
      let connection = await db.getConnection()
      const queryRunner = connection.createQueryRunner()
      await queryRunner.connect()
      // 开始事务
      await queryRunner.startTransaction()
      let noticeList: Notices[] = []
      try {
        //设置答案被拒
        let answerIds = [...new Set([...answerList.map(e => e.id)])]
        let reject_auto_time = new Date()
        await this.answerRepository.createQueryBuilder(null, queryRunner).update({check:0, check_time: reject_auto_time}).where({id: In(answerIds)}).execute()
        //同提问的人发答案
        await this.repository.createQueryBuilder(null, queryRunner).update({answer_time: reject_auto_time, post_answer: 1})
          .where({id: In(questionsList.map(e => e.id))})
          .execute()

        questionsList.map(item => {
          //收到答案通知
          let notice = new Notices()
          notice.video_id = item.video_id
          notice.answer_id = item.answer_id
          notice.wx_user = item.wx_user
          notice.check = 1
          notice.type = NoticeTypeEnum.question_is_answer
          notice.create_time = reject_auto_time
          noticeList.push(notice)
        })

        //添加被拒绝通知
        answerList.map(e => {
          let notice = new Notices()
          notice.create_time = reject_auto_time
          notice.video_id = e.video_id
          notice.wx_user = e.wx_user
          notice.check = NoticeCheckEnum.no
          notice.type = NoticeTypeEnum.answer_reject
          notice.answer_id = e.id
          notice.reject_reason = e.reject_reason
          noticeList.push(notice)
        })
        //保存通知
        await this.noticesRepository.createQueryBuilder(null,queryRunner)
          .insert()
          .into(Notices)
          .values(noticeList)
          .execute()

        await queryRunner.commitTransaction()
        await queryRunner.release();
        
        let noticeWxUserList = [...new Set([...answerList.map(e => e.wx_user),...answerList.map(e => e.questions_wx_user)])]
        noticeWxUserList.map(e => {
          //添加通知
          this.wsStartGateway.postUpdateNotice(e, e)
        })
        let pushVideoIds = [...new Set([...answerList.map(e => e.video_id)])]
        pushVideoIds.map(e => {
          //更新视频数据
          this.wsStartGateway.postUpdateVideo(e)
        })
        //更新我的里数据
        answerList.map(e => {
          this.wsStartGateway.postUpdateMyData(e.wx_user, e.video_id)
        })
        questionsList.map(e => {
          this.wsStartGateway.postUpdateMyData(e.wx_user, e.video_id)
        })
      } catch (err) {
        // 有错误做出回滚更改
        await queryRunner.rollbackTransaction()
        await queryRunner.release();
      }
    }
  }

  @Interval(1000 * 30)
  validUpdateVideoNotSend(){
  }
  
  async findRejectAnswer(nowTime){
    let answerList = await this.answerRepository.query(`
      select distinct answer.*
      from answer
      where reject_auto_time <= ? and reject_auto_time is not null and answer.check is null`
    ,[nowTime])

    let questionsWhere = []
    let where = []
    answerList.map(e => {
      questionsWhere.push(` (questions.group_uid = ? and questions.video_id = ?)`)
      where.push(e.group_uid)
      where.push(e.video_id)
    })
    let questionsList = []
    if(where.length > 0){
      questionsList = await this.repository.query(`
        select questions.*, answer.id as answer_id from questions
        inner join answer on answer.video_id = questions.video_id and answer.check = 1
        where questions.post_answer is null and (${questionsWhere.join(' or ')})
      `, where)
    }
    return { answerList, questionsList }
  }
}
